#include "app_cloud.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "cmsis_os2.h"
#include "ohos_init.h"

#include <dtls_al.h>
#include <mqtt_al.h>
#include <oc_mqtt_al.h>
#include <oc_mqtt_profile.h>
#include "wifi_connect.h"
#include "app_log.h"
#include "string.h"
#include "app_env.h"
#include "app_led.h"
#include "mutex.h"

const static char *TAG = "app_cloud.c";

#define CONFIG_WIFI_SSID "ArsSama" // 修改为自己的WiFi 热点账号
#define CONFIG_WIFI_PWD "88888888" // 修改为自己的WiFi 热点密码
#define CONFIG_APP_SERVERIP "fe676140d0.st1.iotda-device.cn-north-4.myhuaweicloud.com"
#define CONFIG_APP_SERVERPORT "1883"
#define CONFIG_APP_DEVICEID "649f0d009415fc7a573b2eea_qihang_env" // 替换为注册设备后生成的deviceid
#define CONFIG_APP_DEVICEPWD "1424838093"                         // 替换为注册设备后生成的密钥
#define CONGIG_APP_SERVER_NAME "ENV"                              // 设备服务名称
#define CONFIG_APP_LIFETIME 60                                    // seconds

#define CONFIG_QUEUE_TIMEOUT (5 * 1000)

#define MSGQUEUE_COUNT 16
#define MSGQUEUE_SIZE 10

#define TASK_DELAY_5S 300 /* os tick is 10ms */
#define DEBUG 0

char *str;

typedef struct app_cloud_cmd_flag
{
    int rev_light_fan_cmd_flag; /* 1->fan 2->light 0->NULL */
} cloud_cmd_flag;

typedef enum
{
    en_msg_cmd = 0,
    en_msg_report,
} en_msg_type_t;

typedef struct
{
    char *request_id;
    char *payload;
} cmd_t;

typedef struct
{
    int temp; /* 温度 */
    int humi; /* 湿度 */
    int lumi; /* 光照强度 */
} report_t;

typedef struct
{
    en_msg_type_t msg_type;
    union
    {
        cmd_t cmd;
        report_t report;
    } msg;
} app_msg_t;

typedef struct
{
    osMessageQueueId_t app_msg;
    int connected;
    int fan;
    int light;
} app_cb_t;

static app_cb_t g_app_cb;
static cloud_cmd_flag cmd_flag = {0, 0};

/**
 * @brief 处理上报的消息
 *
 * @param report_t 上报结构体
 */
static void deal_report_msg(report_t *report)
{
    oc_mqtt_profile_service_t service;
    oc_mqtt_profile_kv_t temperature;
    oc_mqtt_profile_kv_t humidity;
    oc_mqtt_profile_kv_t luminance;
    oc_mqtt_profile_kv_t fan;
    oc_mqtt_profile_kv_t light;

    if (g_app_cb.connected != 1)
    {
        return;
    }

    service.event_time = NULL;
    service.service_id = CONGIG_APP_SERVER_NAME;
    service.service_property = &temperature;
    service.nxt = NULL;

    temperature.key = "Temperature";
    temperature.value = &report->temp;
    temperature.type = EN_OC_MQTT_PROFILE_VALUE_INT;
    temperature.nxt = &humidity; // 下一个消息的结构体地址

    humidity.key = "Humidity";
    humidity.value = &report->humi;
    humidity.type = EN_OC_MQTT_PROFILE_VALUE_INT;
    humidity.nxt = &luminance; // 下一个消息的结构体地址

    luminance.key = "Luminance";
    luminance.value = &report->lumi;
    luminance.type = EN_OC_MQTT_PROFILE_VALUE_INT;
    luminance.nxt = &fan; // 下一个消息的结构体地址

    fan.key = "FanStatus";
    fan.value = g_app_cb.fan ? "ON" : "OFF";
    fan.type = EN_OC_MQTT_PROFILE_VALUE_STRING;
    fan.nxt = &light;

    light.key = "LightStatus";
    light.value = g_app_cb.light ? "ON" : "OFF";
    light.type = EN_OC_MQTT_PROFILE_VALUE_STRING;
    light.nxt = NULL;

    oc_mqtt_profile_propertyreport(NULL, &service);
    return;
}

// use this function to push all the message to the buffer
static int msg_rcv_callback(oc_mqtt_profile_msgrcv_t *msg)
{
    int ret = 0;
    char *buf;
    int buf_len;
    app_msg_t *app_msg;

    if ((msg == NULL) || (msg->request_id == NULL) || (msg->type != EN_OC_MQTT_PROFILE_MSG_TYPE_DOWN_COMMANDS))
    {
        return ret;
    }

    buf_len = sizeof(app_msg_t) + strlen(msg->request_id) + 1 + msg->msg_len + 1;
    buf = malloc(buf_len);
    if (buf == NULL)
    {
        return ret;
    }
    app_msg = (app_msg_t *)buf;
    buf += sizeof(app_msg_t);

    app_msg->msg_type = en_msg_cmd;
    app_msg->msg.cmd.request_id = buf;
    buf_len = strlen(msg->request_id);
    buf += buf_len + 1;
    memcpy_s(app_msg->msg.cmd.request_id, buf_len, msg->request_id, buf_len);
    app_msg->msg.cmd.request_id[buf_len] = '\0';

    buf_len = msg->msg_len;
    app_msg->msg.cmd.payload = buf;
    memcpy_s(app_msg->msg.cmd.payload, buf_len, msg->msg, buf_len);
    app_msg->msg.cmd.payload[buf_len] = '\0';

    ret = osMessageQueuePut(g_app_cb.app_msg, &app_msg, 0U, CONFIG_QUEUE_TIMEOUT);
    if (ret != 0)
    {
        free(app_msg);
    }

    return ret;
}

static void oc_cmdresp(cmd_t *cmd, int cmdret)
{
    oc_mqtt_profile_cmdresp_t cmdresp;
    ///< do the response
    cmdresp.paras = NULL;
    cmdresp.request_id = cmd->request_id;
    cmdresp.ret_code = cmdret;
    cmdresp.ret_name = NULL;
    (void)oc_mqtt_profile_cmdresp(NULL, &cmdresp);
}
///< COMMAND DEAL
#include <cJSON.h>
static void deal_cmd_msg(cmd_t *cmd)
{
    printf("enter deal_cmd_msg 1\n");
    cJSON *obj_root;
    cJSON *obj_cmdname;
    cJSON *obj_paras;
    cJSON *obj_para;

    int cmdret = 1;

    obj_root = cJSON_Parse(cmd->payload);
    if (obj_root == NULL)
    {
        oc_cmdresp(cmd, cmdret);
    }

    obj_cmdname = cJSON_GetObjectItem(obj_root, "command_name");
    if (obj_cmdname == NULL)
    {
        printf("obj_cmdname == NULL\n");
        cJSON_Delete(obj_root);
    }
    /* 收到风扇操作命令 */
    if (strcmp(cJSON_GetStringValue(obj_cmdname), "command_fan") == 0)
    {
        cmd_flag.rev_light_fan_cmd_flag = 1; /* 下发命令标志置真 */
        printf("command_fan != NULL\n");
        obj_paras = cJSON_GetObjectItem(obj_root, "paras");
        if (obj_paras == NULL)
        {
            printf("paras == NULL\n ");
            cJSON_Delete(obj_root);
        }
        obj_para = cJSON_GetObjectItem(obj_paras, "Fan_Control_fan");
        if (obj_para == NULL)
        {
            printf("Fan_Control_fan == NULL\n");
            cJSON_Delete(obj_root);
        }
        else
        {
            ///< operate the fan here
            str = cJSON_GetStringValue(obj_para);
        }
        cmdret = 0;
        oc_cmdresp(cmd, cmdret);
    }
    /* 收到灯光操作命令 */
    else if (strcmp(cJSON_GetStringValue(obj_cmdname), "command_light") == 0)
    {
        cmd_flag.rev_light_fan_cmd_flag = 2; /* 下发命令标志置真 */
        printf("command_light != NULL\n");
        obj_paras = cJSON_GetObjectItem(obj_root, "paras");
        if (obj_paras == NULL)
        {
            printf("paras == NULL\n ");
            cJSON_Delete(obj_root);
        }
        obj_para = cJSON_GetObjectItem(obj_paras, "Light_Control_light");
        if (obj_para == NULL)
        {
            printf("Light_Control_light == NULL\n");
            cJSON_Delete(obj_root);
        }
        else
        {
            ///< operate the fan here
            str = cJSON_GetStringValue(obj_para);
        }
        cmdret = 0;
        oc_cmdresp(cmd, cmdret);
    }
    return;
}

int CloudMainTaskEntry(void)
{
    app_msg_t *app_msg;
    uint32_t ret;

    WifiConnect(CONFIG_WIFI_SSID, CONFIG_WIFI_PWD);
    dtls_al_init();
    mqtt_al_init();
    oc_mqtt_init();

    g_app_cb.app_msg = osMessageQueueNew(MSGQUEUE_COUNT, MSGQUEUE_SIZE, NULL);
    if (g_app_cb.app_msg == NULL)
    {
        MY_LOGI(TAG, "Create receive msg queue faifan");
    }
    oc_mqtt_profile_connect_t connect_para;
    (void)memset_s(&connect_para, sizeof(connect_para), 0, sizeof(connect_para));

    connect_para.boostrap = 0;
    connect_para.device_id = CONFIG_APP_DEVICEID;
    connect_para.device_passwd = CONFIG_APP_DEVICEPWD;
    connect_para.server_addr = CONFIG_APP_SERVERIP;
    connect_para.server_port = CONFIG_APP_SERVERPORT;
    connect_para.life_time = CONFIG_APP_LIFETIME;
    connect_para.rcvfunc = msg_rcv_callback;
    connect_para.security.type = EN_DTLS_AL_SECURITY_TYPE_NONE;
    ret = oc_mqtt_profile_connect(&connect_para);
    if ((ret == (int)en_oc_mqtt_err_ok))
    {
        g_app_cb.connected = 1;
        MY_LOGI(TAG, "oc_mqtt_profile_connect succed!\r\n");
    }
    else
    {
        MY_LOGI(TAG, "oc_mqtt_profile_connect faild!\r\n");
    }

    while (1)
    {
        app_msg = NULL;
        (void)osMessageQueueGet(g_app_cb.app_msg, (void **)&app_msg, NULL, 0xFFFFFFFF);
        if (app_msg != NULL)
        {
            switch (app_msg->msg_type)
            {
            case en_msg_cmd:
                MY_LOGI(TAG, "en_msg_cmd\n");
                deal_cmd_msg(&app_msg->msg.cmd);
                break;
            case en_msg_report:
                MY_LOGI(TAG, "en_msg_report\n");
                deal_report_msg(&app_msg->msg.report);
                app_msg->msg_type = en_msg_cmd;
                break;
            default:
                break;
            }
            free(app_msg);
        }
    }
    return 0;
}

int SensorTaskEntry(void)
{
    app_msg_t *app_msg;
    int ret;
    uint8_t time;
    while (1)
    {
        /* 处理下发命令 Start */
        osMutexAcquire(ctrl_mutexId, osWaitForever); /* 获取控制状态互斥锁 */
        if (str != NULL)
        {
            time = 0;
            MY_LOGI(TAG, "str: %s\r\n", str);
            if (strstr(str, "ON") != NULL)
            {
                sscanf(str, "ON %d", &time);
                MY_LOGI(TAG, "ON time: %d\n", time);
                if (time != 0)
                {
                    app_env_ctrl_status.cloud_time = time;
                    app_env_ctrl_status.flag_priority = 1;
                    if (cmd_flag.rev_light_fan_cmd_flag == 1)
                    {
                        pwm_ctrl(2, 80);             // ON Fan
                        g_app_cb.fan = 1;            /* 风扇 */
                        app_env_ctrl_status.fan = 1; /* 风扇 */
                    }
                    else if (cmd_flag.rev_light_fan_cmd_flag == 2)
                    {
                        led_ctrl(5, 1, 1);             // ON Light
                        g_app_cb.light = 1;            /* 灯 */
                        app_env_ctrl_status.light = 1; /* 灯 */
                    }
                }
                else
                    app_env_ctrl_status.flag_priority = 0;
            }
            else if (strstr(str, "OFF") != NULL)
            {
                sscanf(str, "OFF %d", &time);
                MY_LOGI(TAG, "OFF time: %d\n", time);
                if (time != 0)
                {
                    app_env_ctrl_status.cloud_time = time;
                    app_env_ctrl_status.flag_priority = 1;
                    if (cmd_flag.rev_light_fan_cmd_flag == 1)
                    {
                        IoTPwmStop(2);               /* OFF Fan */
                        g_app_cb.fan = 0;            /* 风扇 */
                        app_env_ctrl_status.fan = 0; /* 风扇 */
                    }
                    else if (cmd_flag.rev_light_fan_cmd_flag == 2)
                    {
                        led_ctrl(5, 0, 1);             /* ON Fan */
                        g_app_cb.light = 0;            /* 灯 */
                        app_env_ctrl_status.light = 0; /* 灯 */
                    }
                }
                else
                    app_env_ctrl_status.flag_priority = 0;
            }
            cmd_flag.rev_light_fan_cmd_flag = 0;   /* 下发命令标志清零 */
            free(str);
            str = NULL;
        }
        osMutexRelease(ctrl_mutexId); /* 释放控制状态互斥锁 */
        /* 处理下发命令 end */

        app_msg = malloc(sizeof(app_msg_t));
#if DEBUG
        MY_LOGI(TAG, "flag_priority  -> %d\n", app_env_ctrl_status.flag_priority);
        MY_LOGI(TAG, "FanStatus      -> %s\n", g_app_cb.fan ? "ON" : "OFF");
        MY_LOGI(TAG, "LightStatus    -> %s\n", g_app_cb.light ? "ON" : "OFF");
#endif
        if (app_msg != NULL)
        {
            osMutexAcquire(env_mutexId, osWaitForever);               /* 获取环境数据互斥锁 */
            app_msg->msg_type = en_msg_report;                        /* 类型为上报 */
            app_msg->msg.report.temp = (int)app_env_data.Temperature; /* 传入数据为Temp */
            app_msg->msg.report.humi = (int)app_env_data.Humidity;    /* 传入数据为Humi */
            app_msg->msg.report.lumi = (int)app_env_data.Lux;         /* 传入数据为Lumi */
            osMutexRelease(env_mutexId);                              /* 释放环境数据互斥锁 */
            if (app_env_ctrl_status.flag_priority == 0)
            {
                osMutexAcquire(ctrl_mutexId, osWaitForever); /* 获取控制状态互斥锁 */
                g_app_cb.fan = app_env_ctrl_status.fan;      /* 传入数据为风扇状态 */ 
                g_app_cb.light = app_env_ctrl_status.light;  /* 传入数据为灯光状态 */
                osMutexRelease(ctrl_mutexId);                /* 释放控制状态互斥锁 */
            }
            if (osMessageQueuePut(g_app_cb.app_msg, &app_msg, 0U, CONFIG_QUEUE_TIMEOUT) != 0)
            {
                free(app_msg);
            }
        }
        osDelay(TASK_DELAY_5S);
    }
    return 0;
}
